package com.lanyun.gateway.filter;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lanyun.config.properties.JwtProperties;
import com.lanyun.core.constant.JwtClaimsConstant;
import com.lanyun.core.context.LoginContextHolder;
import com.lanyun.gateway.service.JwtService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;

@Component
@Slf4j
public class JwtAuthenticationFilter implements GlobalFilter, Ordered {

    @Resource
    private JwtProperties jwtProperties;

    @Resource
    private JwtService jwtService;

    private static final String ADMIN = "/api-admin";

    private static final String APP = "/api-app";


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String adminToken = exchange.getRequest().getHeaders().getFirst(jwtProperties.getAdminTokenName());

        String appToken = exchange.getRequest().getHeaders().getFirst(jwtProperties.getAppTokenName());

        String path = exchange.getRequest().getPath().toString();

        // 放行白名单请求
        if (jwtProperties.getIgnoreUris().contains(path)) {
            return chain.filter(exchange);
        }

        try {
            if (path.contains(ADMIN)) { // 处理管理端请求
                return handleAdminRequest(exchange, chain, adminToken);
            } else if (path.contains(APP)) { // 处理APP端请求
                return handleAppRequest(exchange, chain, appToken);
            }
        } catch (Exception e) {
            log.error("jwt.error:{}", e.getMessage());
            try {
                throw e;
            } catch (JsonProcessingException ex) {
                throw new RuntimeException(ex);
            }
        }
        return chain.filter(exchange);
    }

    /**
     * 处理管理端请求
     *
     * @param exchange 请求
     * @param chain    过滤器
     * @param token    token
     * @return
     */
    private Mono<Void> handleAdminRequest(ServerWebExchange exchange, GatewayFilterChain chain, String token) {
        return handleRequest(exchange, chain, token, jwtProperties.getAdminSecretKey(), JwtClaimsConstant.ADMIN_USER_ID);
    }

    /**
     * 处理APP端请求
     *
     * @param exchange 请求
     * @param chain    过滤器
     * @param token    token
     * @return
     */
    private Mono<Void> handleAppRequest(ServerWebExchange exchange, GatewayFilterChain chain, String token) throws JsonProcessingException {
        return handleRequest(exchange, chain, token, jwtProperties.getAppSecretKey(), JwtClaimsConstant.APP_USER_ID);
    }

    /**
     * 公共方法处理请求
     *
     * @param exchange    请求
     * @param chain       过滤器
     * @param token       token
     * @param secretKey   密钥
     * @param userIdClaim 用户ID的Claim
     * @return
     */
    private Mono<Void> handleRequest(ServerWebExchange exchange, GatewayFilterChain chain, String token, String secretKey, String userIdClaim) {
        Claims claims = jwtService.validateToken(token, secretKey);
        if (Objects.isNull(claims)) {
            throw new JwtException("JWT 身份校验失败");
        }
        Long userId = Long.valueOf(claims.get(userIdClaim).toString());
        if (userId != null) {
            exchange.getRequest().mutate().header(LoginContextHolder.LOGIN_USER_HEADER, userId.toString());
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE; // 设置过滤器优先级
    }
}